package com.jse.server.websockets;

import java.io.IOException;
import java.security.NoSuchAlgorithmException;

import com.jse.Http;
import com.jse.server.Headers;
import com.jse.server.HttpExchange;
import com.jse.server.HttpHandler;
import com.jse.web.View;

public abstract class WebSocketHandler implements HttpHandler {

    @Override
    public void handle(HttpExchange exchange) throws IOException {
        Headers headers = exchange.getRequestHeaders();

        if (!isWebsocketRequested(headers)) {
            exchange.sendResponseHeaders(Http.HTTP_BAD_REQUEST, 0l);
            return;
        }

        if (!Util.HEADER_WEBSOCKET_VERSION_VALUE.equalsIgnoreCase(headers.getFirst(Util.HEADER_WEBSOCKET_VERSION))) {
        	exchange.status=Http.HTTP_BAD_REQUEST;
            View.text.render(exchange, 
                    "Invalid Websocket-Version " + headers.getFirst(Util.HEADER_WEBSOCKET_VERSION));
            return;
        }

        if (!headers.containsKey(Util.HEADER_WEBSOCKET_KEY)) {
        	exchange.status=Http.HTTP_BAD_REQUEST;
        	View.text.render(exchange, "Missing Websocket-Key");
            return;
        }

        WebSocket webSocket = openWebSocket(exchange);

        try {
            exchange.getResponseHeaders().add(Util.HEADER_WEBSOCKET_ACCEPT,
                    Util.makeAcceptKey(headers.getFirst(Util.HEADER_WEBSOCKET_KEY)));
        } catch (NoSuchAlgorithmException e) {
        	exchange.status=Http.HTTP_INTERNAL_ERROR;
        	View.text.render(exchange,"The SHA-1 Algorithm required for websockets is not available on the server.");
            return;
        }

        if (headers.containsKey(Util.HEADER_WEBSOCKET_PROTOCOL)) {
            exchange.getResponseHeaders().add(Util.HEADER_WEBSOCKET_PROTOCOL,
                    headers.getFirst(Util.HEADER_WEBSOCKET_PROTOCOL).split(",")[0]);
        }

        exchange.getResponseHeaders().add(Util.HEADER_UPGRADE, Util.HEADER_UPGRADE_VALUE);
        exchange.getResponseHeaders().add(Util.HEADER_CONNECTION, Util.HEADER_CONNECTION_VALUE);

        exchange.sendResponseHeaders(101, 0);

        // this won't return until websocket is closed
        webSocket.readWebsocket();
    }

    public static boolean isWebsocketRequested(Headers headers) {
        // check if Upgrade connection
        String connection = headers.getFirst(Util.HEADER_CONNECTION);
        if (connection == null || !connection.toLowerCase().contains(Util.HEADER_CONNECTION_VALUE.toLowerCase())) {
            return false;
        }
        // check for proper upgrade tyoe
        String upgrade = headers.getFirst(Util.HEADER_UPGRADE);
        return Util.HEADER_UPGRADE_VALUE.equalsIgnoreCase(upgrade);
    }

    protected abstract WebSocket openWebSocket(HttpExchange exchange);
}
